
<template>
  <section
    v-if="show"
    class="h-transfer single-tab">
    <div class="mask"></div>
    <!-- 内容面板 -->
    <div class="transfer__content">
      <!-- 面板顶部标题 -->
      <header class="transfer__header">
        <i class="el-icon-monitor"></i>
        {{ title }}
        <i class="el-icon-close" @click="closeTransfer" ></i>
      </header>
      <!-- 穿梭框主要内容 -->
      <div class="transfer__body">
        <!-- 左边穿梭框 -->
        <div class="transfer-pane" style="border-right: 1px solid #dcdfe6 !important">
          <!-- 操作栏 -->
          <!-- <div class="transfer-pane__tools">

          </div> -->
          <!-- 穿梭框 -->
          <div class="transfer-pane__body" style="height: 530px">
            <div class="enough-mask" v-show="isEnough">
              <span class="p-center">最多选择{{ maxNum }}项</span>
            </div>
            <div
              class="searchResPane"
              :class="{ active: searchMode }"
              v-loading="searchLoading" >
              <div class="hidden-tag" @click="searchString = ''">关闭</div>
              <div v-for="(item, index) in searchRes" :key="index" class="item">
                <div>
                  <div>{{ getNodeProp(item, 'label') }}</div>
                  <div class="text-ellipsis search-res-tip" >
                    {{ getNodeProp(item, 'searchResTip') }}
                  </div>
                </div>
                <el-checkbox @change="checked => checked ? addData(item) : removeData(item, true)"></el-checkbox>
              </div>

              <div v-if="searchRes.length <= 0" class="item" style="text-align: center;display:block;">
                无匹配项
              </div>

            </div>

            <el-input
                    v-model="searchString"
                    class="search-input"
                    size="mini"
                    style="width: 95%;height: 40px;"
                    type="search"
                    placeholder="搜索"
                    :disabled="!searchable"
                    prefix-icon="el-icon-search"
            ></el-input>

            <el-divider content-position="right" style="margin: 12px 0px;"></el-divider>

            <el-scrollbar style="height:460px;">

                <el-tree
                  :ref="config.type"
                  :lazy="true"
                  show-checkbox
                  :props="{
                    children: config.children,
                    label: config.label,
                    isLeaf: config.isLeaf,
                    disabled: config.disabled
                  }"
                  :default-expanded-keys="['1']"
                  :load="onLoad"
                  node-key="nodeId"
                  :check-strictly="true"
                  @check-change="(data, checked) => onCheckChange(data, checked)"

                  style="min-height: 370px;"
                >
                </el-tree>

            </el-scrollbar>
          </div>
        </div>
        <!-- 右边穿梭框 -->
        <div class="transfer-pane">
          <div class="transfer-pane__tools">
            <span>
              <span style="margin-right: 1rem;font-size: 14px;">{{ selectedData.length }} / {{ maxNum }}</span>
              <el-tooltip placement="top" content="清空">
                <i class="el-icon-delete" @click="removeAll"></i>
              </el-tooltip>
            </span>
          </div>

          <el-divider content-position="center">已选择</el-divider>

          <el-scrollbar class="transfer-pane__body shadow right-pane">

              <div
                      v-for="(item, index) in selectedData"
                      :key="index"
                      class="selected-item"
              >
                <span>
                  <!-- <i v-if="item.deptName" class="iconfont iconbumen"></i>
                  <i v-else class="iconfont iconyuangong"></i> &nbsp; -->
                  <span>{{ getNodeProp(item, 'label') }}</span>
                </span>
                <i
                        class="el-icon-delete"
                        @click="removeData(item)"
                ></i>
              </div>

              <div
                      v-for="(item, index) in aloneCheckedData"
                      :key="'alone'+ index"
                      class="selected-item"
              >
                <span>
                  <!-- <i v-if="item.deptName" class="iconfont iconbumen"></i>
                  <i v-else class="iconfont iconyuangong"></i> &nbsp; -->
                  <span>{{ getNodeProp(item, 'label') }}</span>
                </span>
                <i
                        class="el-icon-delete"
                        @click="removeData(item, true)"
                ></i>
              </div>

          </el-scrollbar>
          <footer class="transfer__footer" style="float: right">
            <el-button plain size="mini" @click="closeTransfer">取消</el-button>
            <el-button type="primary" plain size="mini" @click="confirm" >确定</el-button >
          </footer>
        </div>
      </div>

    </div>
  </section>
</template>

<script>
/* eslint-disable no-prototype-builtins */
/* eslint-disable no-debugger */
/* eslint-disable no-return-assign */
/* eslint-disable handle-callback-err */

import { CONFIG_LIST } from './config.js'
import { debounce } from '@/assets/utils/index.js'

export default {
  name: 'fc-org-transfer',
  props: {
    // v-model 已经选择过的数据 用于回显
    value: {
      type: Array,
      default: () => ([])
    },
    // 字符串数组使用配置文件的预设值
    // 对象数组需要包含 key/conf 两个属性 conf 会覆盖对应key的默认配置
    type: {
      type: String,
      default: () => 'dep'
    },
    title: {
      type: String,
      default: '组织机构'
    },
    show: {
      type: Boolean,
      reuired: true
    },
    // 是否支持模糊查询
    searchable: {
      type: Boolean,
      default: true
    },
    // 可选择的最大数量
    maxNum: {
      type: Number,
      default: 99
    }
  },
  data () {

    return {
      searchRes: [],  // 搜索后的结果
      selectedData: [],   // 用户手动选择的节点(在tree里面已经显示的节点)
      aloneCheckedData: [], // 已有的 但是未在tree中渲染的数据 例如回显时的数据
      isEnough: false,  // 是否选择了足够的人数
      searchString: '',
      searchMode: false,  // 是否展示搜索面板
      searchLoading: false
    }
  },
  computed: {
    selectedNum () {
      return this.selectedData.length;
    }
  },
  mounted () {
    this.isNumEnough()
    this.debounceSearch = debounce(this.search, 500)
  },
  methods: {
    onLoad (node, resolve) {

      var that = this;

      this.config.onload(node).then(res => {
        const nodes = res.map( t => ( { nodeId: that.config.nodeId(t), ...t } ) )
        resolve(nodes)
      })
      .then(res=>{

        const tree = that.$refs[that.type];

        that.aloneCheckedData.forEach(data => {
          tree.setChecked(data.nodeId, true)
        })
      })
    },

    search () {

      var that = this;

      if (!that.searchString) {

        that.searchRes = []
        return
      }

      that.searchLoading = true

      new Promise((resolve, reject) => {

        that.config.onsearch(that.searchString, resolve, reject)

      }).then(res => {

        console.info(res);

        that.searchRes = res.map(t => ({ nodeId: that.config.nodeId(t), ...t }))

        console.info(that.searchRes);
      })
      .catch(err => console.warn(err))
      .finally(() => that.searchLoading = false)
    },

    onCheckChange (data, checked) {

      var that = this;

      const index = that.aloneCheckedData.findIndex(t => t.nodeId === data.nodeId)

      if (index > -1) {
        that.aloneCheckedData.splice(index, 1)
      }

      that.$nextTick(() => {

        const tree = that.$refs[that.type]

        const nodes = tree.getCheckedNodes().map(t => {
          !t.nodeId && (t.nodeId = that.getNodeProp(t, 'nodeId'))
          return t
        })

        that.selectedData = nodes;

        that.isNumEnough()
        that.$forceUpdate()
      })
    },

    addData (data) {

      const tree = this.$refs[this.type]

      tree.setChecked(data.nodeId, true)
      !tree.getCheckedKeys(data).includes(data.nodeId)
      && !this.aloneCheckedData.find(t => t.nodeId === data.nodeId)
      && this.aloneCheckedData.push(data)
    },

    removeData (data, fromAloneData = false) {

      if (fromAloneData) {

        const index = this.aloneCheckedData.findIndex(t => t.nodeId === data.nodeId)
        index > -1 && this.aloneCheckedData.splice(index, 1)

      } else {

        //取消树节点选中状态
        this.$refs[this.type].setChecked(data.nodeId, false)  // 触发onCheckChange
      }
    },

    removeAll () {

      const tree = this.$refs[this.type]

      tree.getCheckedKeys().forEach(function(key){
        tree.setCheckedKeys([])
      })

      this.selectedData = []
      this.aloneCheckedData = []
    },

    isNumEnough () {

      let count = 0
      count += this.selectedData.length
      count += this.aloneCheckedData.length

      this.isEnough = (count >= this.maxNum ? true : false)
    },

    closeTransfer () {
      this.$emit('update:show', false)
      this.isEnough = false
      this.searchString = ''
    },

    confirm () {

      var selectedData = this.selectedData;

      var selectedDataMap = {};

      for(var i = 0; i < selectedData.length; i ++){
        selectedDataMap[selectedData[i].nodeId] = selectedData[i];
      }

      for(var i = 0; i < this.aloneCheckedData.length; i ++){

        if(!selectedDataMap[this.aloneCheckedData[i].nodeId]){
          selectedData.push(this.aloneCheckedData[i]);
        }
      }

      this.$emit('confirm', JSON.parse(JSON.stringify(selectedData)))
      this.closeTransfer()
    },

    getConfProp(propName){

      return this.config ? this.config[propName] : null
    },

    getNodeProp(data, propName){
      try{

        console.info("data:" + JSON.stringify(data))
        console.info("propName:" + propName)

        const prop = this.getConfProp(propName)

        console.info("prop:" + JSON.stringify(prop))

        if(typeof prop === 'string'){
          return data[prop]
        }
        if(typeof prop === 'function'){
          return prop(data)
        }
      }catch(e){
        console.error(e)
        return '执行出错，可联系开发人员'
      }
    },

    dataInit(){

      var that = this;

      this.aloneCheckedData = []
      this.selectedData = []
      this.config = {}


        CONFIG_LIST.find(function(cfg){

          if(cfg.type == that.type){

            that.config = cfg;
          }
        })

      if(that.value && that.value.length > 0){

        for(var i = 0; i < that.value.length; i++){
          that.value[i].nodeId = that.config.nodeId(that.value[i]);
        }

        that.aloneCheckedData = that.value;
      }
    }
  },
  watch: {
    searchString (newVal) {
      this.searchMode = !!newVal
      this.debounceSearch()
    },

    show: {
      handler: function (show) {
        if (show) {
          this.dataInit()
          this.isNumEnough()
        }
      },
      immediate: true
    },

    type:{
      handler: function(val){
        this.dataInit() // type 比show 延后
      },
      immediate: true,
      deep: true
    }
  }
}
</script>
<style lang="stylus">
.h-transfer{
  text-align: left;
  position: fixed;
  width: 100vw;
  height: 100vh;
  top: 0;
  left: 0;
  z-index: 2999;
  line-height: 32px;

  > .mask {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.5);
  }

  .el-tabs--border-card {
    box-shadow: none;
  }

  .el-tabs__content {
    overflow: visible;
    min-height: 250px;
  }

  .el-tabs__nav {
    width: 100%;
    display: flex;

    > .el-tabs__item {
      flex-grow: 1;
    }
  }

  &.single-tab .el-tabs__item {
    text-align: center;
    background: #f5f7fa !important;
    border-bottom: 1px solid #e4e7ed;
    border-right-width: 0px;
  }

  .el-tree-node__content > label.el-checkbox {
    // position: absolute;
    // right: 0;
  }

  .searchResPane{
    position: absolute;
    overflow-y: auto;
    z-index: 99;
    left: 0;
    top: 100%;
    width: 100%;
    height: 100%;
    background: white;
    border: 1px solid #dcdfe6;
    transition: top .5s;
    margin-top: 50px;



    &.active{
        top: 0;
    }

    .hidden-tag{
        color:#999;
        font-size:12px;
        text-align:right;
        padding-top:4px;
        padding-right:12px;
        cursor pointer

        &:hover{
            color: #66b1ff;
        }
    }

    .item{
        padding: 4px 14px;
        display: flex;
        justify-content: space-between;
        align-items: center;
        line-height 1.5
        &:hover{
            background-color: #ecf5ff;
            color: #66b1ff;
            cursor: pointer;
        }

        .search-res-tip{
          font-size:12px;
          color:#999;
          max-width: 280px;
        }
    }
  }

  .enough-mask{
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    color: white;
    font-size: 16px;
    z-index: 100;
    height: 100%;
    background: rgba(0,0,0,0.5);
    letter-spacing: 4px;
  }

  .p-center{
      position absolute
      top 50%
      left 50%
      transform translate(-50%, -50%)
  }

  .transfer__content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 800px;
  height: 600px;
  background: white;
  overflow: hidden;
  border-radius: 4px;


  .el-divider--horizontal {
    display: block;
    height: 1px;
    width: 100%;
    margin-right: 0px;
    margin-left: 0px;
    margin-top: 12px;
    margin-bottom: 12px;
  }

  .el-input__inner{
    height: 40px;
    line-height: 40px;
  }
}

.transfer__header {
  margin-bottom: 6px;
  background: #565656;
  padding: 6px 24px;
  color: white;
  .el-icon-close{
    cursor:pointer;
    float: right;
    margin-top: 10px;
  }
}


.transfer__body {
  padding: 12px 0;
  display: flex;
  justify-content: space-around;
}

.transfer-pane {
  width: 360px;
}
  .search-input  input{
    border: 1px solid #DCDFE6 !important;
    &:focus{
      border-color:#409EFF !important;
    }
  }

.transfer-pane__tools {
  margin-bottom: 0px!important;
  height: 40px!important;
  display: block!important;
  justify-content: space-between;
  align-items: center;
  text-align: right;
  padding-right: 13px;



  span:last-child {
    cursor: pointer;
  }
}

.transfer-pane__body {
  position relative
  width: 100%;
  height: 330px;
  overflow hidden
  font-size: 14px;

  >>> .el-scrollbar__view{
    height: 100%;
  }

  .el-tabs__item {
    height: 26px;
    line-height: 26px;
  }

  .el-scrollbar__view {
    overflow-x: visible!important;
  }


  .is-disabled
  {
    display: none;
  }
}

.transfer-icons {
  display: flex;
  flex-direction: column;
  justify-content: center;

  i {
    margin-top: 20px;
    margin-bottom: 20px;
    cursor: pointer;
    font-size: 20px;
    color: #696969;

    &:hover {
      transform: scale(1.1);
    }
  }
}

.tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;

  .node-label {
    max-width: 250px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
  }

  .node-checkbox {
    position: absolute;
    right: 0;
  }

  i {
    &:hover {
      color: #1485f8;
      cursor: pointer;
    }

    font-size: 10px;
  }

}

.right-pane {
  box-sizing: border-box;
  overflow-x: hidden;
  height: 430px!important;
  margin-bottom: 10px;

  .selected-item {
    padding: 0px 12px;
    display: flex;
    justify-content: space-between;
    align-items: center;

    &:hover {
      background-color: #F5F7FA;
    }

    span {
      max-width: 90%;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    i {
      &:hover {
        color: #1485f8;
        cursor: pointer;
      }
    }
  }
}

.dot{
  width: 2px;
  height: 2px;
  display: inline-block;
  border-radius: 50%;
  background: #4caf50;
}

  .text-ellipsis{
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}
</style>
